package gui;

import java.io.File;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;

import network.Client;
import network.InfoMsg;
import network.JoinGameMsg;
import network.NetworkGame;
import network.NetworkPlayer;
import network.OpenGameMsg;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import resources.images.ImagesPath;

public class NetworkGameDialog extends Dialog {

	protected Object result;
	public static Shell shell;
	private Composite typeComposite;
	private Composite openGamesComposite;
	private Composite startComposite;
	private Composite createGameComposite;
	@SuppressWarnings("unused")
	private String serverIP;
	@SuppressWarnings("unused")
	private String nickname;
	@SuppressWarnings("unused")
	private int numOfPlayers;
	private Text serverIPText;
	private Text nicknameText;
	private Text numOfPlayersText;
	private RiskGUI gui;
	private Label info;
	private static List openGames;

	//concurrent
	public static ReentrantLock lock = new ReentrantLock();
	public volatile static boolean needToUpdate = false;
	public volatile static Map<Integer, NetworkGame> games;
	private static Label joinLabel;
	private boolean connected = false;
	private boolean waiting = false;
	private Button connectButton;


	/**
	 * Create the dialog
	 * @param parent
	 * @param style
	 */
	public NetworkGameDialog(Shell parent, int style) {
		super(parent, style);
	}

	/**
	 * Create the dialog
	 * @param parent
	 */
	public NetworkGameDialog(Shell parent) {
		this(parent, SWT.NONE);
	}

	public NetworkGameDialog(Shell parent, RiskGUI gui) {
		this(parent, SWT.NONE);
		this.gui = gui;
	}

	/**
	 * Open the dialog
	 * @return the result
	 */
	public Object open() {
		Client.setDialog(this);
		createContents();
		shell.open();
		shell.layout();
		Display display = getParent().getDisplay();
		/*while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
			if(NetworkGameDialog.needToUpdate){
				NetworkGameDialog.lock.lock();
				try{
					updateOpenGames();
				} finally {
					NetworkGameDialog.lock.unlock();
				}
			}
		}*/
		return result;
	}

	/**
	 * Create contents of the dialog
	 */
	protected void createContents() {
		shell = new Shell(getParent(), SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
		shell.addShellListener(new ShellAdapter() {
			public void shellClosed(final ShellEvent e) {
				if(!connected) return;
				if(waiting){
					MessageDialog msg = new MessageDialog(shell,"Exit?",null,"You are still waiting for the game to start. Are you sure you want to exit?",MessageDialog.QUESTION,new String[] {"Yes","No"},1);
					if(msg.open()==1){
						e.doit = false;
						return;
					}
				}
				Client.closeConnection();
			}
		});
		//shell.setLocation(RiskGUI.getNewPosition(getParent()));
		shell.setSize(400, 540);
		shell.setText("Network Game");
		Composite composite = new Composite(shell, SWT.NONE);
		composite.setSize(400, 512);
		composite.setBackgroundImage(new Image(Display.getDefault(),ImagesPath.getImageStream("mission.png")));
		composite.setBackgroundMode(SWT.INHERIT_DEFAULT);
		Composite serverIPComposite = new Composite(composite, SWT.NONE);
		serverIPComposite.setBounds(30, 80, 340, 30);
		String separator = File.separator;
		Font font = FontLoader.loadFont(
				shell, 
				"src" + separator + "resources" + separator + "fonts" + separator + "papyrus.ttf", 
				13);

		Label serverIPLabel = new Label(serverIPComposite, SWT.NONE);
		serverIPLabel.setSize(100, 30);
		serverIPLabel.setFont(font);
		serverIPLabel.setText("Server IP: ");
		serverIPText = new Text(serverIPComposite, SWT.BORDER);
		serverIPText.setFont(font);
		serverIPText.setBounds(100, 0, 150, 30);

		Composite nameComposite = new Composite(composite, SWT.NONE);
		nameComposite.setBounds(30, 115, 340, 30);
		Label nameLabel = new Label(nameComposite, SWT.NONE);
		nameLabel.setSize(100, 30);
		nameLabel.setFont(font);
		nameLabel.setText("Nickname: ");
		nicknameText = new Text(nameComposite, SWT.BORDER);
		nicknameText.setFont(font);
		nicknameText.setBounds(100, 0, 150, 30);
		connectButton = new Button(nameComposite, SWT.NONE);
		connectButton.setBounds(255, 0,80, 30);
		connectButton.setFont(font);
		connectButton.setText("Connect");
		connectButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				String serverIP = serverIPText.getText();
				String name = nicknameText.getText();
				
				//checking
				if(name.trim().length()==0){
					//printInfo("Please insert your name", true);
					nicknameText.setText("guest");
					name = nicknameText.getText();
				}
				if(serverIP.trim().length()==0){
					printInfo("Please insert an IP", true);
					return;
				}
				
				if(connect(serverIP, name)){
					connected = true;
				} else {
					connected = false;
				}
				//updateOpenGames();
			}
		});

		openGamesComposite = new Composite(composite, SWT.NONE);
		openGamesComposite.setBounds(30, 150, 340, 195);
		openGames = new List (openGamesComposite, SWT.BORDER | SWT.V_SCROLL);
		//		for (int i=0; i<128; i++) 
		//			openGames.add ("Game " + i);
		openGames.setBounds (0, 0, 340, 195);
		openGames.setFont(font);
		
		Font fontBig = FontLoader.loadFont(
				shell, 
				"src" + separator + "resources" + separator + "fonts" + separator + "papyrus.ttf", 
				20);
		
		createGameComposite = new Composite(composite, SWT.NONE);
		createGameComposite.setBounds(30, 150, 340, 195);
		Label numOfPlayersLabel = new Label(createGameComposite, SWT.NONE);
		numOfPlayersLabel.setSize(200, 30);
		numOfPlayersLabel.setFont(font);
		numOfPlayersLabel.setText("Number of players (2-6): ");
		numOfPlayersText = new Text(createGameComposite, SWT.BORDER);
		numOfPlayersText.setBounds(200, 0, 30, 30);
		numOfPlayersText.setFont(font);
		
		startComposite = new Composite(composite, SWT.NONE);
		startComposite.setBounds(30, 350, 340, 40);
		final Label startLabel = new Label(startComposite, SWT.NONE);
		startLabel.setAlignment(SWT.CENTER);
		startLabel.setBounds(138, 0, 70, 40);
		startLabel.setFont(fontBig);
		startLabel.setText("Start");
		startLabel.addMouseListener(new MouseAdapter() {
			public void mouseDown(MouseEvent arg) {
				nickname = nicknameText.getText();
				try{
					numOfPlayers = Integer.valueOf(numOfPlayersText.getText());
					if(numOfPlayers < 2 || numOfPlayers > 6){
						printInfo("Illegal number of players", true);
						return;
					}
				}catch(NumberFormatException e){
					printInfo("Illegal number of players", true);
					return;
				}
				Client.sendMsg(new OpenGameMsg(nickname, numOfPlayers));
				startLabel.setEnabled(false);
				numOfPlayersText.setEnabled(false);
				printInfo("Waiting for other players...", false);
			}
		});

		Label joinedPlayers = new Label(createGameComposite, SWT.NONE);
		joinedPlayers.setFont(font);
		joinedPlayers.setBounds(0, 35, 340, 160);
		//		joinedPlayers.setAlignment(SWT.CENTER);
		//		String players = "";
		//		for(int i=0; i<6; i++){
		//			players += "Player " + i + "\n";
		//			joinedPlayers.setText(players);
		//		}
		
		typeComposite = new Composite(composite, SWT.NONE);
		typeComposite.setBounds(30, 350, 340, 40);
		Label joinLabel = new Label(typeComposite, SWT.NONE);
		joinLabel.setAlignment(SWT.CENTER);
		joinLabel.setBounds(80, 0, 70, 40);
		joinLabel.setFont(fontBig);
		joinLabel.setText("Join");
		joinLabel.addMouseListener(new MouseAdapter() {
			public void mouseDown(MouseEvent arg) {
				nickname = nicknameText.getText();
				if (!NetworkGameDialog.games.keySet().isEmpty()) {
					if (NetworkGameDialog.openGames.getSelectionIndex() == -1) {
						printInfo("Choose the game you want to join", true);
		
					}
					else {
						String selection = NetworkGameDialog.openGames.getSelection()[0].split(":")[0];
						if (!RiskGUI.isUserInDB()){
							String searchFor = "guest";
							int len = searchFor.length();
							int result = 0;
							if (len > 0) {  
								int start = selection.indexOf(searchFor);
								while (start != -1) {
									result++;
								    start = selection.indexOf(searchFor, start+len);
								}
							}
							result++;
							Client.setName("guest" + result);
							RiskGUI.setUsername("guest" + result);
							RiskGUI.setUserInDB(false);
							RiskGUI.setUsernameProperties("");
						}
						Client.sendMsg(new JoinGameMsg(Integer.valueOf(selection.split(" ")[1]), Client.getName()));
						printInfo("Waiting for other players...", false);
					}
				}
				else {
					printInfo("There are no open games to join", true);
				}

			}
		});

		Label createLabel = new Label(typeComposite, SWT.NONE);
		createLabel.setAlignment(SWT.CENTER);
		createLabel.setBounds(160, 0, 100, 40);
		createLabel.setFont(fontBig);
		createLabel.setText("Create");
		createLabel.addMouseListener(new MouseAdapter() {
			public void mouseDown(MouseEvent e) {
				switchToCreateView();
			}
		});

		
		Composite infoComposite = new Composite(composite, SWT.NONE);
		infoComposite.setBounds(30, 400, 340, 30);
		info = new Label(infoComposite, SWT.NONE);
		info.setSize(340, 30);
		info.setFont(font);
		info.setAlignment(SWT.CENTER);
		//		info.setText("Info");


		switchToJoinView();

		typeComposite.setVisible(false);
		openGamesComposite.setVisible(false);
		//
	}

	public static void updateOpenGames(){
		if(shell.isDisposed()) return;
		openGames.removeAll();
		String entry;
		for(int index : NetworkGameDialog.games.keySet()) {
			NetworkGame game = NetworkGameDialog.games.get(index);
			entry = "Game " + index + ": ";
			for(NetworkPlayer player : game.getPlayers()){
				entry += player.getName() + ", ";
			}
			openGames.add(entry);
			NetworkGameDialog.needToUpdate = false;
		}
	}

	protected boolean connect(String serverIP, String name) {
		Client.setGui(gui);
		Client.setServerIP(serverIP);
		Client.setName(name);
		printInfo("Waiting for server...", false);
		if(!Client.connect()){
			//error
			printInfo("Connections refused. Check the IP.", true);
			return false;
		} else {
			new Thread(new Client()).start();
			typeComposite.setVisible(true);
			openGamesComposite.setVisible(true);
			printInfo("Connected to server", true);
			serverIPText.setEnabled(false);
			nicknameText.setEnabled(false);
			connectButton.setEnabled(false);
			RiskGUI.setUsername(name);
			RiskGUI.setUserInDB(false);
			if (!nicknameText.getText().equalsIgnoreCase("guest")){
				UserLogin login = new UserLogin(shell, gui);
				login.open();
				nicknameText.setText(RiskGUI.getUsername());
			}
			else
				nicknameText.setText("guest");
			return true;
		}
	}

	//	private void clearInfo() {
	//		printInfo("", false);
	//	}

	private void printInfo(String info, boolean delay){
		this.info.setText(info);
		if(delay){
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			this.info.setText("");
		} else {
			waiting = true;
		}
	} 

	private void switchToCreateView(){
		shell.setText("Create Network Game");

		typeComposite.setVisible(false);
		openGamesComposite.setVisible(false);

		startComposite.setVisible(true);
		createGameComposite.setVisible(true);
	}

	private void switchToJoinView(){
		shell.setText("Join Network Game");

		typeComposite.setVisible(true);
		openGamesComposite.setVisible(true);

		startComposite.setVisible(false);
		createGameComposite.setVisible(false);
	}

	public static void main(String[] args){
		Shell shell = new Shell();
		NetworkGameDialog dialog = new NetworkGameDialog(shell);
		dialog.open();
	}

}
